﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Input;
using AppMachine.Domain.LogicCom.AppComs;
using AppMachine.Entities;
using AppMachine.EntityFrameworkCore.Repositories.LogicCom;
using AppMachine.EntityFrameworkCore.Repositories.PerpDev;
using PerpheralDevice;
using PerpheralDevice.Units;
using Prism.Commands;
using Prism.Mvvm;

namespace AppMachine.Models
{

    public class AxisDebugModel : BindableBase {

        private AxisType _AxisType = AxisType.X;
        /// <summary>
        /// 轴类型
        /// </summary>
        public AxisType AxisType {
            get => _AxisType;
            set { SetProperty(ref _AxisType, value); }
        }

        private string _AxisName = default;
        /// <summary>
        /// 轴名称
        /// </summary>
        public string AxisName {
            get => _AxisName;
            set { SetProperty(ref _AxisName, value); }
        }

        private double? _PosCommand = default;
        /// <summary>
        /// 轴 当前 命令位置
        /// </summary>
        public double? PosCommand {
            get => _PosCommand;
            set { SetProperty(ref _PosCommand, value); }
        }

        private double? _PosEncoder = default;
        /// <summary>
        /// 轴 当前 反馈位置
        /// </summary>
        public double? PosEncoder {
            get => _PosEncoder;
            set { SetProperty(ref _PosEncoder, value); }
        }

        private double? _VelRun = default;
        /// <summary>
        /// 当前执行速度
        /// </summary>
        public double? VelRun {
            get => _VelRun;
            set { SetProperty(ref _VelRun, value); }
        }

        private bool? _StateSVON = default(bool?);
        public bool? StateSVON {
            get => _StateSVON;
            set { SetProperty(ref _StateSVON, value); }
        }

        private bool? _StateORG = default(bool?);
        public bool? StateORG {
            get => _StateORG;
            set { SetProperty(ref _StateORG, value); }
        }

        private bool? _StateMEL = default(bool?);
        public bool? StateMEL {
            get => _StateMEL;
            set { SetProperty(ref _StateMEL, value); }
        }

        private bool? _StatePEL = default(bool?);
        public bool? StatePEL {
            get => _StatePEL;
            set { SetProperty(ref _StatePEL, value); }
        }

        private bool? _StateMDN = default(bool?);
        /// <summary>
        /// 是否完成运动: 可能是异常停止
        /// </summary>
        public bool? StateMDN {
            get => _StateMDN;
            set { SetProperty(ref _StateMDN, value); }
        }

        private bool? _StateINP = default(bool?);
        /// <summary>
        /// 是否正常完成运动(运动指令值与编码器值 近似)
        /// </summary>
        public bool? StateINP {
            get => _StateINP;
            set { SetProperty(ref _StateINP, value); }
        }       
        
        private bool? _StateALM = default(bool?);
        public bool? StateALM {
            get => _StateALM;
            set { SetProperty(ref _StateALM, value); }
        }

        private bool? _StateASTP = default(bool?);
        public bool? StateASTP {
            get => _StateASTP;
            set { SetProperty(ref _StateASTP, value); }
        }

        
        private void MfMotor_OnStatusChanged(PerpDevUnit perpDevUnit) {
            App.Current.Dispatcher.InvokeAsync(() => {
                if (perpDevUnit is Motor tempMotor) {
                    this.UpdateIoUI(tempMotor.MotorStatus);
                }                
            }, System.Windows.Threading.DispatcherPriority.ApplicationIdle);
        }

        private void UpdateIoUI(MotorStatus motorStatus) {
            this.StateALM = motorStatus.MIO_ALM;
            this.StateMEL = motorStatus.MIO_MEL;
            this.StatePEL = motorStatus.MIO_PEL;
            this.StateORG = motorStatus.MIO_ORG;            
            this.StateASTP = motorStatus.MIO_EMG;
            this.StateSVON = motorStatus.MIO_SVON;
            this.StateINP = motorStatus.MIO_INP;
            this.StateMDN = motorStatus.MTS_MDN;
            this.PosCommand = this.mfComMotor.Motor.PosCommand;
            this.PosEncoder = this.mfComMotor.Motor.PosEncoder;
            this.VelRun = this.mfComMotor.VelWork;
        }

        private readonly ComMotor mfComMotor = null;
        public AxisDebugModel(ComMotor comMotor) {
            this.mfComMotor = comMotor;
            this.AxisName = $"{this.mfComMotor.ComConfig.ComID}-{this.mfComMotor.ComConfig.TagName}";
            this.AxisType = Enum.Parse<AxisType>(this.mfComMotor.AppType);
            
            if (this.mfComMotor.Motor != null) {
                this.UpdateIoUI(this.mfComMotor.Motor.MotorStatus);
                this.mfComMotor!.Motor.Add<Motor>(MfMotor_OnStatusChanged);
            }
        }

        public ICommand ResetCommand => new DelegateCommand(() => {
            this.mfComMotor.Reset();
        });
        public ICommand MovePositiveCommand => new DelegateCommand(() => {
            this.mfComMotor.VelWorkSet(this.VelRun ?? 10).ReachRel(10);
        });
        public ICommand MoveNegativeCommand => new DelegateCommand(() => {
            this.mfComMotor.VelWorkSet((int)(this.VelRun ?? 1000)).ReachRel(-1000);
        });
        public ICommand StopCommand => new DelegateCommand(() => {
            this.mfComMotor.Stop();
        });
        public ICommand DoMovingCommand => new DelegateCommand<bool?>((isForward) => {
            double? tempVel = isForward ?? false ? this.VelRun : -this.VelRun;
            this.mfComMotor.VelWorkSet(tempVel ?? 1000).DoMoving();
        });

    }

    public class AxisDebugModelCollecton : BindableBase {
        public AxisDebugModelCollecton() {
            AppComRepository.GetInstance().GetAll<ComMotor>().OrderBy(it=>it.ComConfig.ComIndex).ToList().ForEach(tempComMotor => {
                this.SourceList.Add(new AxisDebugModel(tempComMotor));
            });
            this.AxisCurrent = this.SourceList.FirstOrDefault();
        }

        private AxisDebugModel? _AxisCurrent = default(AxisDebugModel);
        /// <summary>
        /// 当前操作的轴
        /// </summary>
        public AxisDebugModel? AxisCurrent {
            get => _AxisCurrent;
            set { SetProperty(ref _AxisCurrent, value); }
        }
        /// <summary>
        /// 左右可操作的轴列表
        /// </summary>
        public ObservableCollection<AxisDebugModel> SourceList { get; set; } = new();
    }

}
